package com.swdegao.iot.netty.server.qianbaotonghandler;

import com.swdegao.iot.netty.utils.ConvertUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

@Slf4j
public class QianBaoTongDecoder extends ByteToMessageDecoder {

    private final ByteBuf header;
    private final ByteBuf ender;

    public QianBaoTongDecoder() {
        this.header = Unpooled.buffer();
        header.writeByte(0x7B);
        header.writeByte(0x01);
        header.writeByte(0x00);
        header.writeByte(0x16);
        this.ender = Unpooled.buffer();
        ender.writeByte(0x45);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        // 显示十六进制的接收码
        log.info("当前in中 可读缓存数据为{}", ByteBufUtil.hexDump(in));
        // 调用tryDecode方法，去除帧头和帧尾
        ByteBuf childBuf = tryDecode(in);
        // 如果获得有效数据
        if (childBuf != null) {
            // 将有效数据备份加入接收列表
            out.add(childBuf);
        }
    }

    private ByteBuf tryDecode(ByteBuf buf) {
        // 帧头起始位置
        int sliceStart = 0;
        // 帧尾起始位置
        int sliceEnd = 0;
        // 数据帧
        ByteBuf frame = null;
        // 帧头存在
        if (header != null) {
            // 获取帧头位置
            int index = ByteBufUtil.indexOf(header, buf);
            // 帧头第一次出现位置找到
            if (index > -1 && index < buf.capacity()) {
                // 舍弃帧头前面的数据
                buf.readerIndex(index);
            }
            // 将帧头位置保存
            sliceStart = index;
        }
        // 帧尾存在
        if (ender != null) {
//            byte[] bufBytes = new byte[buf.readableBytes()];//全量转字节数组
//            buf.getBytes(0,bufBytes);
//            System.out.println(new String(bufBytes));


            // 获取帧尾的起始位置
            int endIndex = ByteBufUtil.indexOf(ender, buf);//第一个尾部字节出现的位置
            if(endIndex==-1 ){
                return null;//未找到帧尾，继续等待
            }

            sliceEnd = endIndex;

            byte[] barray = new byte[sliceEnd - sliceStart  + ender.readableBytes()];//第一个0x45 的位置，可能存在多个0x45
            buf.getBytes(sliceStart,barray);//复制可能是完整的帧，头尾的数据存到 barray
            byte[] crcBarray = Arrays.copyOfRange(barray,25,barray.length-3);//控制码+数据域长度，获取计算crc的数据段
            byte[] res = QianBaoTong.crc188(crcBarray);//计算crc
            byte crcA = barray[barray.length-3];
            byte crcB = barray[barray.length-2];

            if(res[0] == crcA && res[1] == crcB){
                System.out.println("CRC校验成功");
                int length = sliceEnd - sliceStart  + ender.readableBytes();//计算数据帧的长度，结束位置+帧尾部1个字节0X45-起始位置
                frame = buf.retainedSlice(sliceStart, length);// 获取数据子帧
                buf.readerIndex(sliceEnd + ender.readableBytes());//重置读指针
//                buf.skipBytes(sliceEnd - sliceStart + ender.readableBytes());// 将reader索引设定到帧尾的后面
                log.info("buf 重置读指针，缓存当前数据为{}", ByteBufUtil.hexDump(buf));
                return frame;// 将数据帧返回
            }else{
                return getFrameByExistMoreEnder( buf, frame, sliceStart, sliceEnd, endIndex);
            }


        }

        return null;
    }


    private ByteBuf getFrameByExistMoreEnder(ByteBuf buf,ByteBuf frame,int sliceStart,int sliceEnd,int endIndex){
        //进行下一个0X45查找
        int endIndexMore = ByteBufUtil.indexOf(buf, endIndex + 1,buf.readableBytes(), (byte) 0x45);//第一个校验和不合法，继续寻找第二个0x45
        if(endIndexMore == -1){
            return null;//未找到帧尾，继续等待
        }
        sliceEnd = endIndexMore;
        byte[] newBarray = new byte[sliceEnd - sliceStart  + ender.readableBytes()];//发现的下一个0x45 的位置，可能存在多个0x45
        buf.getBytes(sliceStart,newBarray);//复制可能是完整的帧，头尾的数据存到 barray
        byte[] crcNewBarray = Arrays.copyOfRange(newBarray,25,newBarray.length-3);//控制码+数据域长度，获取计算crc的数据段
        byte[] newRes = QianBaoTong.crc188(crcNewBarray);//计算crc
        byte newCrcA = newBarray[newBarray.length-3];
        byte newCrcB = newBarray[newBarray.length-2];
        if(newRes[0] == newCrcA && newRes[1] == newCrcB){
            System.out.println("CRC校验成功");
            int length = sliceEnd - sliceStart  + ender.readableBytes();//计算数据帧的长度，结束位置+帧尾部1个字节0X45-起始位置
            frame = buf.retainedSlice(sliceStart, length);// 获取数据子帧
            buf.readerIndex(sliceEnd + ender.readableBytes());//重置读指针
//            buf.skipBytes(sliceEnd - sliceStart + ender.readableBytes());// 将reader索引设定到帧尾的后面
            log.info("getFrameByExistMoreEnder-buf 重置读指针，缓存当前数据为{}", ByteBufUtil.hexDump(buf));
            return frame;// 将数据帧返回
        }else{
            return getFrameByExistMoreEnder(buf,frame,sliceStart,sliceEnd,endIndexMore);
        }
    }



}
